<template>
  <div id="customShaderBox"></div>
</template>

<script>
import InitCesium from "@/lib/initCesium.js";
import "cesium/Build/Cesium/Widgets/widgets.css";
import * as Cesium from "cesium";

export default {
  data() {
    return {
      viewerObj: null,
    };
  },
  mounted() {
    this.init();
  },
  unmounted() {
    this.viewerObj.destroy();
  },
  methods: {
    init() {
      this.viewerObj = InitCesium.init("customShaderBox");

      function CustomPrimitive(cartographicPosition) {
        this.show = true;
        this.drawCommand = undefined;
        this.faceResolution = 200;
        this.cartographicPosition = cartographicPosition;
        var cartesianPosition = Cesium.Cartographic.toCartesian(
          cartographicPosition,
          Cesium.Ellipsoid.WGS84,
          new Cesium.Cartesian3()
        );
        this.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(
          cartesianPosition,
          Cesium.Ellipsoid.WGS84,
          new Cesium.Matrix4()
        );

        this.halfWidthMeters = 10000;
        this.boundingSphere = new Cesium.BoundingSphere(
          cartesianPosition,
          this.halfWidthMeters * Math.SQRT2
        );

        this.time = undefined;
      }

      function generateVertices(faceResolution, halfWidthMeters) {
        var vertexResolution = faceResolution + 1;
        var vertexCount = vertexResolution * vertexResolution;
        var componentsPerVertex = 3;
        var vertices = new Float32Array(vertexCount * componentsPerVertex);
        for (var i = 0; i < vertexResolution; i++) {
          for (var j = 0; j < vertexResolution; j++) {
            var u = i / (vertexResolution - 1);
            var v = j / (vertexResolution - 1);
            var index = i * vertexResolution + j;
            var x = halfWidthMeters * (2 * u - 1);
            var y = halfWidthMeters * (2 * v - 1);
            var z = 0;

            vertices[index * componentsPerVertex] = x;
            vertices[index * componentsPerVertex + 1] = y;
            vertices[index * componentsPerVertex + 2] = z;
          }
        }
        return vertices;
      }

      function generateIndices(faceResolution) {
        var indicesPerQuad = 6;
        var indexCount = faceResolution * faceResolution * indicesPerQuad;
        var indices = new Uint16Array(indexCount);

        var vertexResolution = faceResolution + 1;

        var quadIndex = 0;
        for (var i = 0; i < faceResolution; i++) {
          for (var j = 0; j < faceResolution; j++) {
            var a = i * vertexResolution + j;
            var b = i * vertexResolution + (j + 1);
            var c = (i + 1) * vertexResolution + (j + 1);
            var d = (i + 1) * vertexResolution + j;

            indices[quadIndex * indicesPerQuad] = a;
            indices[quadIndex * indicesPerQuad + 1] = b;
            indices[quadIndex * indicesPerQuad + 2] = c;
            indices[quadIndex * indicesPerQuad + 3] = c;
            indices[quadIndex * indicesPerQuad + 4] = d;
            indices[quadIndex * indicesPerQuad + 5] = a;
            quadIndex++;
          }
        }

        return indices;
      }

      var scratchColor = new Cesium.Color();
      function generateTexture(context) {
        var width = 256;
        var textureTypedArray = new Uint8Array(width * 4);
        for (var i = 0; i < width; i++) {
          var bucket32 = 32 * Math.floor(i / 32);
          var bucket4 = 4 * Math.floor(i / 4);
          var color = Cesium.Color.fromHsl(
            bucket32 / width,
            bucket32 / width,
            (255 - bucket4) / width,
            1.0,
            scratchColor
          );
          textureTypedArray[4 * i] = 255 * color.red;
          textureTypedArray[4 * i + 1] = 255 * color.green;
          textureTypedArray[4 * i + 2] = 255 * color.blue;
          textureTypedArray[4 * i + 3] = 255 * color.alpha;
        }

        return new Cesium.Texture({
          context: context,
          pixelFormat: Cesium.PixelFormat.RGBA,
          pixelDataType:
            Cesium.ComponentDatatype.fromTypedArray(textureTypedArray),
          source: {
            width: width,
            height: 1,
            arrayBufferView: textureTypedArray,
          },
          flipY: false,
          sampler: new Cesium.Sampler({
            minificationFilter: Cesium.TextureMinificationFilter.NEAREST,
            magnificationFilter: Cesium.TextureMagnificationFilter.NEAREST,
          }),
        });
      }

      function initialize(primitive, context) {
        var vertexShader = `
          attribute vec3 a_position;
          varying vec3 v_position;
          varying vec4 v_color;
          uniform float u_time;
          void main(){
            v_color = vec4(0.2,.37,.75,1.);
            float z = 0.0;
            vec2 dir = vec2(0.0006,0.0);
            float width = czm_pi / 4.;           
            float speed = 2.5;
            z += 800.* sin(dot(dir , vec2(a_position.x , a_position.y) ) * width + u_time * speed / 1000.);
            v_color *= (z + 1.) / 800.;
            v_position = a_position;
            gl_Position = czm_modelViewProjection * vec4(a_position.xy, z, 1.0);
          }
          `;

        var fragmentShader =
          "varying vec3 v_position;\n" +
          "varying vec4 v_color;\n" +
          "uniform float u_time;\n" +
          "uniform sampler2D u_texture;\n" +
          "void main()\n" +
          "{\n" +
          "    vec2 k = vec2(0.0004, 0.0001);\n" +
          "    vec2 k2 = vec2(0.0001, 0.0004);\n" +
          "    float z = 0.0;\n" +
          "    z = 1.8 + 0.5 * z;\n" +
          "    gl_FragColor = vec4(v_color.x + .3 ,v_color.yzw + .3 ) * 1.3;\n" +
          "}\n";

        var positionLocation = 0;
        var attributeLocations = {
          a_position: positionLocation,
        };

        var renderState = Cesium.RenderState.fromCache({
          depthTest: {
            enabled: true,
          },
        });

        var shaderProgram = Cesium.ShaderProgram.fromCache({
          context: context,
          vertexShaderSource: vertexShader,
          fragmentShaderSource: fragmentShader,
          attributeLocations: attributeLocations,
        });

        var positionTypedArray = generateVertices(
          primitive.faceResolution,
          primitive.halfWidthMeters
        );
        var positionVertexBuffer = Cesium.Buffer.createVertexBuffer({
          context: context,
          typedArray: positionTypedArray,
          usage: Cesium.BufferUsage.STATIC_DRAW,
        });

        var positionAttribute = {
          index: positionLocation,
          vertexBuffer: positionVertexBuffer,
          componentsPerAttribute: 3,
          componentDatatype:
            Cesium.ComponentDatatype.fromTypedArray(positionTypedArray),
        };

        var indexCount =
          primitive.faceResolution * primitive.faceResolution * 6;
        var indexTypedArray = generateIndices(primitive.faceResolution);
        var indexBuffer = Cesium.Buffer.createIndexBuffer({
          context: context,
          typedArray: indexTypedArray,
          indexDatatype:
            Cesium.ComponentDatatype.fromTypedArray(indexTypedArray),
          usage: Cesium.BufferUsage.STATIC_DRAW,
        });

        var vertexArray = new Cesium.VertexArray({
          context: context,
          attributes: [positionAttribute],
          indexBuffer: indexBuffer,
        });

        var texture = generateTexture(context);

        primitive.time = performance.now();
        var uniformMap = {
          u_time: function () {
            var now = performance.now();
            return now - primitive.time;
          },
          u_texture: function () {
            return texture;
          },
        };

        var drawCommand = new Cesium.DrawCommand({
          boundingVolume: primitive.boundingSphere,
          modelMatrix: primitive.modelMatrix,
          pass: Cesium.Pass.OPAQUE,
          shaderProgram: shaderProgram,
          renderState: renderState,
          vertexArray: vertexArray,
          count: indexCount,
          primitiveType: Cesium.PrimitiveType.TRIANGLES,
          uniformMap: uniformMap,
        });
        primitive.drawCommand = drawCommand;
      }

      CustomPrimitive.prototype.update = function (frameState) {
        if (!this.show) {
          return;
        }
        if (!Cesium.defined(this.drawCommand)) {
          initialize(this, frameState.context);
        }
        frameState.commandList.push(this.drawCommand);
      };

      var position = new Cesium.Cartographic(0, 0, 0.0);
      this.viewerObj.scene.primitives.add(new CustomPrimitive(position));
      this.viewerObj.camera.flyTo({
        destination: Cesium.Cartesian3.fromDegrees(0, 0, 50000),
        duration: 2,
      });
    },
  },
};
</script>

<style>
#customShaderBox {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}
</style>
